#ifndef LINE_H
#define LINE_H

#include "value.h"
#include "pool.h"
#include "closure.h"
#include "collector.h"
#include "instruction.h"
#include "string.h"
#include "queue.h"
#include "map.h"

typedef struct Globe
{
    Map strings;
    Map keywords;
    Pool pool;
} Globe;

Globe GLOBE;

String s_and, s_false, s_return, s_break, s_continu, s_return, s_if, s_let, s_nil, s_not, s_or, s_true, s_for, s_in, s_function, s_elseif, s_else, s_import, s_from, s_package, s_integer, s_decimal, s_boolean, s_string, s_queue, s_map, s_object, s_try, s_catch;

__attribute__((constructor)) static void GOLBOE_STATIC_INIT()
{
    String keywords[29];
    const u_byte *keywords_cstr[] = {"and", "false", "return", "break", "continu", "return", "if", "let", "nil", "not", "or", "true", "for", "in", "function", "elseif", "else", "import", "from", "package", "integer", "decimal", "boolean", "string", "queue", "map", "object", "try", "catch"};
    const TOKEN_CATEGORY keywords_token[] = {TOKEN_AND, TOKEN_FALSE, TOKEN_RETURN, TOKEN_BREAK, TOKEN_CONTINUE, TOKEN_RETURN, TOKEN_IF, TOKEN_LET, TOKEN_NIL, TOKEN_NOT, TOKEN_OR, TOKEN_TRUE, TOKEN_FOR, TOKEN_IN, TOKEN_FUNCTION, TOKEN_ELSEIF, TOKEN_ELSE, TOKEN_IMPORT, TOKEN_FROM, TOKEN_PACKAGE, TOKEN_INTEGER_TYPE, TOKEN_DECIMAL_TYPE, TOKEN_BOOLEAN_TYPE, TOKEN_STRING_TYPE, TOKEN_QUEUE_TYPE, TOKEN_MAP_TYPE, TOKEN_OBJECT_TYPE, TOKEN_TRY, TOKEN_CATCH

    };
    Pool_Init(&GLOBE.pool, (u_short[16][2]){
                               {8, 64},
                               {16, 96},
                               {24, 128},
                               {32, 256},
                               {48, 256},
                               {64, 128},
                               {128, 64},
                               {256, 48},
                               {512, 32},
                               {1024, 24},
                               {2048, 24},
                               {4096, 16},
                               {8192, 16},
                               {0, 0},
                           });
    Map_Init(&GLOBE.strings, 64);
    Map_Init(&GLOBE.keywords, 32);
    for (size_t i = 0; i < 29; i++)
    {
        String_Init(&keywords[i], keywords_cstr[i]);
        Map_Put(&GLOBE.keywords, TSTRING(&keywords[i]), TINTEGER(keywords_token[i]));
    }
}

static void *Globe_Malloc(u_int size)
{
    return Pool_Malloc(&GLOBE.pool, size);
}

static void *Globe_Calloc(u_int size)
{
    return Pool_Calloc(&GLOBE.pool, size);
}

static void *Globe_Realloc(void *pointer, u_int size)
{
    return Pool_Realloc(&GLOBE.pool, pointer, size);
}

static void Globe_Free(void *ptr)
{
    Pool_Free(&GLOBE.pool, ptr);
}

static String *GLOBE_CREATE_STRING(const u_byte *source)
{
    String *str = Globe_Malloc(sizeof(String));
    String_Init(str, source);
    if (str->length <= 64)
    {
        TValue value = Map_Get(&GLOBE.strings, TSTRING(str));
        if (IS_NULL(value))
        {
            Map_Put(&GLOBE.strings, TSTRING(str), TSTRING(str));
            return str;
        }
        else
        {
            str->delete ((Object *)str);
            Globe_Free(str);
            return (String *)value.value.object;
        }
    }
    return str;
}

typedef struct Exception
{
    TValue key;
    TValue value;
} Exception;

typedef struct Line
{
    Collector collector;
    Array closure_stack;
    Array value_stack;
    Map packages;
    Exception exception;
} Line;

void Line_Init(Line *line);
Exception *Line_DoFile(Line *Line, const _byte *path);
Line *Line_DoString(Line *Line, _byte *string);
void Line_Throw(Line *Line, Exception *exception);
void Line_Run(Line *Line);

#endif